﻿// Decompiled with JetBrains decompiler
// Type: TaleWorlds.MountAndBlade.View.MissionViews.MissionItemContourControllerView
// Assembly: TaleWorlds.MountAndBlade.View, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: 61152EB8-513B-4D4A-8AC0-0D1465C6CF6C
// Assembly location: D:\steam\steamapps\common\Mount & Blade II Bannerlord\Modules\Native\bin\Win64_Shipping_Client\TaleWorlds.MountAndBlade.View.dll

using System;
using System.Collections.Generic;
using System.Linq;
using TaleWorlds.Core;
using TaleWorlds.DotNet;
using TaleWorlds.Engine;
using TaleWorlds.Library;

#nullable disable
namespace TaleWorlds.MountAndBlade.View.MissionViews
{
  public class MissionItemContourControllerView : MissionView
  {
    private GameEntity[] _tempPickableEntities = new GameEntity[128];
    private UIntPtr[] _pickableItemsId = new UIntPtr[128];
    private List<GameEntity> _contourItems;
    private GameEntity _focusedGameEntity;
    private IFocusable _currentFocusedObject;
    private bool _isContourAppliedToAllItems;
    private bool _isContourAppliedToFocusedItem;
    private uint _nonFocusedDefaultContourColor = new Color(0.85f, 0.85f, 0.85f).ToUnsignedInteger();
    private uint _nonFocusedAmmoContourColor = new Color(0.0f, 0.73f, 1f).ToUnsignedInteger();
    private uint _nonFocusedThrowableContourColor = new Color(0.051f, 0.988f, 0.18f).ToUnsignedInteger();
    private uint _nonFocusedBannerContourColor = new Color(0.521f, 0.988f, 0.521f).ToUnsignedInteger();
    private uint _focusedContourColor = new Color(1f, 0.84f, 0.35f).ToUnsignedInteger();
    private float _lastItemQueryTime;
    private float _sceneItemQueryFreq = 1f;

    private bool _isAllowedByOption => !BannerlordConfig.HideBattleUI || GameNetwork.IsMultiplayer;

    public MissionItemContourControllerView() => this._contourItems = new List<GameEntity>();

    public override void OnMissionScreenTick(float dt)
    {
      base.OnMissionScreenTick(dt);
      if (!this._isAllowedByOption)
        return;
      if (Agent.Main != null && this.MissionScreen.InputManager.IsGameKeyDown(5))
      {
        this.RemoveContourFromAllItems();
        this.PopulateContourListWithNearbyItems();
        this.ApplyContourToAllItems();
        this._lastItemQueryTime = this.Mission.CurrentTime;
      }
      else
      {
        this.RemoveContourFromAllItems();
        this._contourItems.Clear();
      }
      if (!this._isContourAppliedToAllItems)
        return;
      float currentTime = this.Mission.CurrentTime;
      if ((double) currentTime - (double) this._lastItemQueryTime <= (double) this._sceneItemQueryFreq)
        return;
      this.RemoveContourFromAllItems();
      this.PopulateContourListWithNearbyItems();
      this._lastItemQueryTime = currentTime;
    }

    public override void OnFocusGained(
      Agent agent,
      IFocusable focusableObject,
      bool isInteractable)
    {
      base.OnFocusGained(agent, focusableObject, isInteractable);
      if (((!this._isAllowedByOption ? 0 : (focusableObject != this._currentFocusedObject ? 1 : 0)) & (isInteractable ? 1 : 0)) == 0)
        return;
      this._currentFocusedObject = focusableObject;
      if (focusableObject is UsableMissionObject standingPoint)
      {
        if (standingPoint is SpawnedItemEntity spawnedItemEntity)
          this._focusedGameEntity = spawnedItemEntity.GameEntity;
        else if (!string.IsNullOrEmpty(standingPoint.ActionMessage.ToString()) && !string.IsNullOrEmpty(standingPoint.DescriptionMessage.ToString()))
        {
          this._focusedGameEntity = standingPoint.GameEntity;
        }
        else
        {
          UsableMachine machineFromPoint = this.GetUsableMachineFromPoint(standingPoint);
          if (machineFromPoint != null)
            this._focusedGameEntity = machineFromPoint.GameEntity;
        }
      }
      this.AddContourToFocusedItem();
    }

    public override void OnFocusLost(Agent agent, IFocusable focusableObject)
    {
      base.OnFocusLost(agent, focusableObject);
      if (!this._isAllowedByOption)
        return;
      this.RemoveContourFromFocusedItem();
      this._currentFocusedObject = (IFocusable) null;
      this._focusedGameEntity = (GameEntity) null;
    }

    private void PopulateContourListWithNearbyItems()
    {
      this._contourItems.Clear();
      float num1 = Agent.Main.MaximumForwardUnlimitedSpeed * (GameNetwork.IsSessionActive ? 1f : 3f);
      Vec3 boundingBoxMin = Agent.Main.Position - new Vec3(num1, num1, 1f);
      Vec3 boundingBoxMax = Agent.Main.Position + new Vec3(num1, num1, 1.8f);
      int num2 = this.Mission.Scene.SelectEntitiesInBoxWithScriptComponent<SpawnedItemEntity>(ref boundingBoxMin, ref boundingBoxMax, this._tempPickableEntities, this._pickableItemsId);
      for (int index = 0; index < num2; ++index)
      {
        SpawnedItemEntity firstScriptOfType = this._tempPickableEntities[index].GetFirstScriptOfType<SpawnedItemEntity>();
        if (firstScriptOfType != null)
        {
          if (firstScriptOfType.IsBanner())
          {
            if (MissionGameModels.Current.BattleBannerBearersModel.IsInteractableFormationBanner(firstScriptOfType, Agent.Main))
              this._contourItems.Add(firstScriptOfType.GameEntity);
          }
          else
            this._contourItems.Add(firstScriptOfType.GameEntity);
        }
      }
      int num3 = this.Mission.Scene.SelectEntitiesInBoxWithScriptComponent<UsableMachine>(ref boundingBoxMin, ref boundingBoxMax, this._tempPickableEntities, this._pickableItemsId);
      for (int index = 0; index < num3; ++index)
      {
        UsableMachine firstScriptOfType = this._tempPickableEntities[index].GetFirstScriptOfType<UsableMachine>();
        if (firstScriptOfType != null && !firstScriptOfType.IsDisabled)
        {
          GameEntity withoutDistanceCheck = firstScriptOfType.GetValidStandingPointForAgentWithoutDistanceCheck(Agent.Main);
          if ((NativeObject) withoutDistanceCheck != (NativeObject) null && !(withoutDistanceCheck.GetFirstScriptOfType<UsableMissionObject>() is SpawnedItemEntity) && withoutDistanceCheck.GetScriptComponents().FirstOrDefault<ScriptComponentBehavior>((Func<ScriptComponentBehavior, bool>) (sc => sc is IFocusable)) is IFocusable focusable && focusable is UsableMissionObject)
            this._contourItems.Add(firstScriptOfType.GameEntity);
        }
      }
    }

    private void ApplyContourToAllItems()
    {
      if (this._isContourAppliedToAllItems)
        return;
      foreach (GameEntity contourItem in this._contourItems)
      {
        uint nonFocusedColor = this.GetNonFocusedColor(contourItem);
        uint num = (NativeObject) contourItem == (NativeObject) this._focusedGameEntity ? this._focusedContourColor : nonFocusedColor;
        contourItem.SetContourColor(new uint?(num));
      }
      this._isContourAppliedToAllItems = true;
    }

    private uint GetNonFocusedColor(GameEntity entity)
    {
      ItemObject itemObject = entity.GetFirstScriptOfType<SpawnedItemEntity>()?.WeaponCopy.Item;
      WeaponComponentData primaryWeapon = itemObject?.PrimaryWeapon;
      ItemObject.ItemTypeEnum? itemType = itemObject?.ItemType;
      if ((itemObject != null ? (itemObject.HasBannerComponent ? 1 : 0) : 0) != 0)
        return this._nonFocusedBannerContourColor;
      if (primaryWeapon == null || !primaryWeapon.IsAmmo)
      {
        ItemObject.ItemTypeEnum? nullable = itemType;
        ItemObject.ItemTypeEnum itemTypeEnum1 = ItemObject.ItemTypeEnum.Arrows;
        if (!(nullable.GetValueOrDefault() == itemTypeEnum1 & nullable.HasValue))
        {
          nullable = itemType;
          ItemObject.ItemTypeEnum itemTypeEnum2 = ItemObject.ItemTypeEnum.Bolts;
          if (!(nullable.GetValueOrDefault() == itemTypeEnum2 & nullable.HasValue))
          {
            nullable = itemType;
            ItemObject.ItemTypeEnum itemTypeEnum3 = ItemObject.ItemTypeEnum.Bullets;
            if (!(nullable.GetValueOrDefault() == itemTypeEnum3 & nullable.HasValue))
            {
              nullable = itemType;
              ItemObject.ItemTypeEnum itemTypeEnum4 = ItemObject.ItemTypeEnum.Thrown;
              return nullable.GetValueOrDefault() == itemTypeEnum4 & nullable.HasValue ? this._nonFocusedThrowableContourColor : this._nonFocusedDefaultContourColor;
            }
          }
        }
      }
      return this._nonFocusedAmmoContourColor;
    }

    private void RemoveContourFromAllItems()
    {
      if (!this._isContourAppliedToAllItems)
        return;
      foreach (GameEntity contourItem in this._contourItems)
      {
        if ((NativeObject) this._focusedGameEntity == (NativeObject) null || (NativeObject) contourItem != (NativeObject) this._focusedGameEntity)
          contourItem.SetContourColor(new uint?());
      }
      this._isContourAppliedToAllItems = false;
    }

    private void AddContourToFocusedItem()
    {
      if (!((NativeObject) this._focusedGameEntity != (NativeObject) null) || this._isContourAppliedToFocusedItem)
        return;
      this._focusedGameEntity.SetContourColor(new uint?(this._focusedContourColor));
      this._isContourAppliedToFocusedItem = true;
    }

    private void RemoveContourFromFocusedItem()
    {
      if (!((NativeObject) this._focusedGameEntity != (NativeObject) null) || !this._isContourAppliedToFocusedItem)
        return;
      if (this._contourItems.Contains(this._focusedGameEntity))
        this._focusedGameEntity.SetContourColor(new uint?(this._nonFocusedDefaultContourColor));
      else
        this._focusedGameEntity.SetContourColor(new uint?());
      this._isContourAppliedToFocusedItem = false;
    }

    private UsableMachine GetUsableMachineFromPoint(UsableMissionObject standingPoint)
    {
      GameEntity gameEntity = standingPoint.GameEntity;
      while (gameEntity != null && !gameEntity.HasScriptOfType<UsableMachine>())
        gameEntity = gameEntity.Parent;
      if ((NativeObject) gameEntity != (NativeObject) null)
      {
        UsableMachine firstScriptOfType = gameEntity.GetFirstScriptOfType<UsableMachine>();
        if (firstScriptOfType != null)
          return firstScriptOfType;
      }
      return (UsableMachine) null;
    }
  }
}
